home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libgutil / rgn.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  13KB  |  849 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    rgn -
  19.  *        Management of regions.
  20.  *
  21.  *                Paul Haeberli - 1986
  22.  */
  23. #include "rct.h"
  24. #include "rgn.h"
  25.  
  26. #ifdef NOTDONE
  27. rgnrectinside(pt,rgn);
  28. #endif
  29.  
  30. #define RGN_UNION    1
  31. #define RGN_INTERSECT    2
  32. #define RGN_DIFF    3
  33.  
  34. #define LEFT        1        /* don't change this!! */
  35. #define RIGHT        0
  36.  
  37. #define OP1        1
  38. #define OP2        2
  39.  
  40. #define BIGY        1000000
  41. #define NINCHUNK    20
  42.  
  43. typedef struct Edge {
  44.     struct Edge *next;
  45.     int side;
  46.     int op;
  47.     int xpos;
  48.     int xmax;
  49.     int ymax;
  50.     rctlist *rect;
  51. } Edge;
  52.  
  53. #define STATIC static
  54.  
  55. STATIC doscan();
  56. STATIC rctlist *incorporate();
  57. STATIC operate();
  58. STATIC quickop();
  59. STATIC deleteold();
  60. STATIC rctlist *addtoactive();
  61. STATIC addedge();
  62. STATIC nexty();
  63. STATIC quickunion();
  64. STATIC Edge *newedge();
  65. STATIC freeedge();
  66. STATIC freeedgelist();
  67. STATIC rctlist *newrl();
  68. STATIC freerl();
  69. STATIC freerectlist();
  70.  
  71. static Edge *fedges = 0;
  72. static rctlist *frls = 0;
  73. static Edge *active, *endactive;
  74. static Edge *opactive;
  75. static Edge *newopactive;
  76. static int nop1, nop2;
  77.  
  78. Edge *newedge();
  79. rctlist *newrl();
  80. rctlist *addtoactive();
  81. rctlist *incorporate();
  82.  
  83. rgn *rgnnew()
  84. {
  85.     rgn *r; 
  86.  
  87.     r = (rgn *)mymalloc(sizeof(rgn));
  88.     r->domain.xmin = 0;
  89.     r->domain.ymin = 0;
  90.     r->domain.xmax = 0;
  91.     r->domain.ymax = 0;
  92.     r->rects = 0;
  93.     return r;
  94. }
  95.  
  96. rgnfree(r)
  97. rgn *r;
  98. {
  99.     freerectlist(r);
  100.     free(r);
  101. }
  102.  
  103. rgn *rgnclone(r)
  104. rgn *r;
  105. {
  106.     rgn *c; 
  107.     rctlist *rl, *crl;;
  108.  
  109.     c = rgnnew();
  110.     *c = *r;
  111.  
  112.     crl = 0;
  113.     rl = r->rects;
  114.     while(rl) {
  115.     if(!crl) {
  116.         c->rects = newrl();
  117.         crl = c->rects;
  118.     } else {
  119.         crl->next = newrl();
  120.         crl = crl->next;
  121.     }
  122.     crl->rect = rl->rect;
  123.     crl->next = 0;
  124.     rl = rl->next;
  125.     }
  126.     return c;
  127. }
  128.  
  129. rgncopy(src,dst)
  130. rgn *src, *dst;
  131. {
  132.     rctlist *rl, *crl;;
  133.  
  134.     if(src == dst)
  135.     return;
  136.     freerectlist(dst);
  137.     *dst = *src;
  138.     crl = 0;
  139.     rl = src->rects;
  140.     while(rl) {
  141.     if(!crl) {
  142.         dst->rects = newrl();
  143.         crl = dst->rects;
  144.     } else {
  145.         crl->next = newrl();
  146.         crl = crl->next;
  147.     }
  148.     crl->rect = rl->rect;
  149.     crl->next = 0;
  150.     rl = rl->next;
  151.     }
  152. }
  153.  
  154. rgnsetempty(r)
  155. rgn *r;
  156. {
  157.     freerectlist(r);
  158.     r->domain.xmin = 0;
  159.     r->domain.ymin = 0;
  160.     r->domain.xmax = 0;
  161.     r->domain.ymax = 0;
  162. }
  163.  
  164. rgnsetrect(r,x1,y1,x2,y2)
  165. rgn *r;
  166. int x1, x2, y1, y2;
  167. {
  168.     freerectlist(r);
  169.     r->rects = newrl();
  170.     r->rects->next = 0;
  171.     rctset(&r->rects->rect,x1,y1,x2,y2);
  172.     rctset(&r->domain,x1,y1,x2,y2);
  173. }
  174.  
  175. rgnrect(r,rect)
  176. rgn *r;
  177. rct *rect;
  178. {
  179.     freerectlist(r);
  180.     r->rects = newrl();
  181.     r->rects->rect = *rect;
  182.     r->rects->next = 0;
  183.     r->domain = *rect;
  184. }
  185.  
  186. rgnequal(r1,r2)
  187. rgn *r1, *r2;
  188. {
  189.     rctlist *rl1, *rl2;
  190.  
  191.     if(r1 == r2)
  192.     return 1;
  193.     if(!rctequal(&r1->domain,&r2->domain))
  194.     return 0;
  195.     rl1 = r1->rects;
  196.     rl2 = r2->rects;
  197.     while(rl1 && rl2) {
  198.     if(!rctequal(&rl1->rect,&rl2->rect))
  199.         return 0;
  200.     rl1 = rl1->next;
  201.     rl2 = rl2->next;
  202.     }
  203.     if(rl1 || rl2)
  204.     return 0;
  205.     else 
  206.     return 1;
  207. }
  208.  
  209. rgnempty(r)
  210. rgn *r;
  211. {
  212.     if(r->rects)
  213.     return 0;
  214.     else
  215.     return 1;
  216. }
  217.  
  218. rgninside(r,x,y)
  219. rgn *r;
  220. int x, y;
  221. {
  222.     rctlist *rl; 
  223.  
  224.     if(rgnempty(r))
  225.     return 0;
  226.     else {
  227.     rl = r->rects;
  228.     while(rl) {
  229.         if(rctinside(&rl->rect,x,y))
  230.         return 1;
  231.         rl = rl->next;
  232.     }
  233.     return 0;
  234.     } 
  235. }
  236.  
  237. rgnoffset(r,dx,dy)
  238. rgn *r;
  239. int dx, dy;
  240. {
  241.     rctlist *rl;
  242.     
  243.     rctoffset(&r->domain,dx,dy);
  244.     rl = r->rects;
  245.     while(rl) {
  246.     rctoffset(&rl->rect,dx,dy);
  247.     rl = rl->next;
  248.     }
  249. }
  250.  
  251. rgnshrink(r,dx,dy)
  252. rgn *r;
  253. int dx, dy;
  254. {
  255.     rgn *temp;
  256.  
  257.     temp = rgnclone(r);
  258.     rgnoffset(temp,dx/2,dy/2);
  259.     rgncopy(temp,r);
  260.     rgnoffset(temp,-dx,0);
  261.     rgnintersect(temp,r,r);
  262.     rgnoffset(temp,0,-dy);
  263.     rgnintersect(temp,r,r);
  264.     rgnoffset(temp,dx,0);
  265.     rgnintersect(temp,r,r);
  266.     rgnfree(temp);
  267. }
  268.  
  269. rgnshadow(r,dx,dy)
  270. rgn *r;
  271. int dx, dy;
  272. {
  273.     rgn *temp;
  274.  
  275.     temp = rgnclone(r);
  276.     rgnoffset(temp,dx,dy);
  277.     rgndiff(temp,r,r);
  278.     rgnfree(temp);
  279. }
  280.  
  281. rgndraw(r)
  282. rgn *r;
  283. {
  284.     rctlist *rl;
  285.     rct temp;
  286.     
  287.     rl = r->rects;
  288.     while(rl) {
  289.     temp = rl->rect;
  290.     rctshrink(&temp,1,1);
  291.     rctdraw(&temp);
  292.     rl = rl->next;
  293.     }
  294. }
  295.  
  296. rgnfill(r)
  297. rgn *r;
  298. {
  299.     rctlist *rl;
  300.     
  301.     rl = r->rects;
  302.     while(rl) {
  303.     rctfill(&rl->rect);
  304.     rl = rl->next;
  305.     }
  306. }
  307.  
  308. rgnsetdomain(r)
  309. rgn *r;
  310. {
  311.     int xmin, xmax, ymin, ymax;
  312.     rct *d;
  313.     rctlist *rl;
  314.  
  315.     rl = r->rects;
  316.     if(!rl) {
  317.     r->domain.xmin = 0;
  318.     r->domain.ymin = 0;
  319.     r->domain.xmax = 0;
  320.     r->domain.ymax = 0;
  321.     } else {
  322.     d = &r->domain;
  323.     *d = rl->rect;
  324.     while(rl) {
  325.         rctunion(&rl->rect,d,d);
  326.         rl = rl->next;
  327.     }
  328.     }
  329. }
  330.  
  331. rgntouch(r1,r2)
  332. rgn *r1, *r2;
  333. {
  334.     if(rgnempty(r1))
  335.     return 0;
  336.     if(rgnempty(r2))
  337.     return 0;
  338.     if(r1->domain.xmin>(r2->domain.xmax+1))
  339.     return 0;
  340.     if(r2->domain.xmin>(r1->domain.xmax+1))
  341.     return 0;
  342.     if(r1->domain.ymin>(r2->domain.ymax+1))
  343.     return 0;
  344.     if(r2->domain.ymin>(r1->domain.ymax+1))
  345.     return 0;
  346.     return 1;
  347. }
  348.  
  349. rgnunion(src1,src2,dst)
  350. rgn *src1, *src2, *dst;
  351. {
  352.     rgn *d;
  353.  
  354.     if(!rgntouch(src1,src2)) {
  355.     quickunion(src1,src2,dst);
  356.     return;
  357.     }
  358.     if(rgnempty(src1)) {
  359.     rgncopy(src2,dst);
  360.     return;
  361.     }
  362.     if(rgnempty(src2)) {
  363.     rgncopy(src1,dst);
  364.     return;
  365.     }
  366.     if(rgnequal(src1,src2)) {
  367.     rgncopy(src1,dst);
  368.     return;
  369.     }
  370.     d = rgnnew();
  371.     doscan(src1,src2,d,RGN_UNION);
  372.     freerectlist(dst);
  373.     *dst = *d;
  374.     free(d);
  375. }
  376.  
  377. rgnintersect(src1,src2,dst)
  378. rgn *src1, *src2, *dst;
  379. {
  380.     rgn *d;
  381.  
  382.     if(!rgntouch(src1,src2)) {
  383.     rgnsetempty(dst);
  384.     return;
  385.     }
  386.     if(rgnempty(src1) || rgnempty(src2)) {
  387.     rgnsetempty(dst);
  388.     return;
  389.     }
  390.     if(rgnequal(src1,src2)) {
  391.     rgncopy(src1,dst);
  392.     return;
  393.     }
  394.     d = rgnnew();
  395.     doscan(src1,src2,d,RGN_INTERSECT);
  396.     freerectlist(dst);
  397.     *dst = *d;
  398.     free(d);
  399. }
  400.  
  401. rgndiff(src1,src2,dst)
  402. rgn *src1, *src2, *dst;
  403. {
  404.     rgn *d;
  405.  
  406.     if(!rgntouch(src1,src2)) {
  407.     rgncopy(src1,dst);
  408.     return;
  409.     }
  410.     if(rgnempty(src1) || rgnequal(src1,src2)) {
  411.     rgnsetempty(dst);
  412.     return;
  413.     }
  414.     if(rgnempty(src2)) {
  415.     rgncopy(src1,dst);
  416.     return;
  417.     }
  418.     d = rgnnew();
  419.     doscan(src1,src2,d,RGN_DIFF);
  420.     freerectlist(dst);
  421.     *dst = *d;
  422.     free(d);
  423. }
  424.  
  425. STATIC doscan(src1,src2,dst,op)
  426. rgn *src1, *src2, *dst;
  427. int op;
  428. {
  429.     int y;
  430.     rctlist *rl1, *rl2;
  431.     rctlist *dstend;
  432.  
  433.     rl1 = src1->rects;
  434.     rl2 = src2->rects;
  435.     dst->rects = 0;
  436.     active = 0;
  437.     nop1 = nop2 = 0;
  438.     opactive = 0;
  439.     newopactive = 0;
  440.     dstend = 0;
  441.     while( (y=nexty(rl1,rl2)) != BIGY ) {
  442.     deleteold(y);
  443.     if(rl1)
  444.         rl1 = addtoactive(y,rl1,OP1);
  445.     if(rl2)
  446.         rl2 = addtoactive(y,rl2,OP2);
  447.     operate(op);
  448.     dstend = incorporate(dst,dstend,y);
  449.     }
  450.     rgnsetdomain(dst);
  451. }
  452.  
  453. STATIC rctlist *incorporate(dst,end,y)
  454. rgn *dst;
  455. rctlist *end;
  456. int y;
  457. {
  458.     Edge *new, *old, *temp;
  459.     int x, donew;
  460.  
  461.     new = newopactive;
  462.     old = opactive;
  463.     while(new || old) {
  464.     donew = 0;
  465.  
  466.     if(new && old) {
  467.         if(old->xpos == new->xpos)     {    
  468.         if(old->xmax == new->xmax) {        /* no change ? */
  469.             new->rect = old->rect;
  470.             old = old->next;
  471.             new = new->next;
  472.         } else {
  473.             old->rect->rect.ymax = y-1;        /* kill old rect */
  474.             old = old->next;
  475.             donew = 1;                 /* make new rect */
  476.         }
  477.         } else {
  478.         if(old->xpos<new->xpos) {         
  479.             old->rect->rect.ymax = y-1;        /* kill old rect */
  480.             old = old->next;
  481.         } else 
  482.             donew = 1;                 /* make new rect */
  483.         }
  484.     } else if(!new && old) {
  485.         old->rect->rect.ymax = y-1;            /* kill old rect */
  486.         old = old->next;
  487.     } else if(!old && new) 
  488.         donew = 1;                     /* make new rect */
  489.  
  490.     if(donew) {
  491.         if(!end) {
  492.         end = dst->rects = newrl();
  493.         } else {
  494.         end->next = newrl();
  495.         end = end->next;
  496.         }
  497.         new->rect = end;
  498.         end->rect.xmin = new->xpos;
  499.         end->rect.ymin = y;
  500.         end->rect.xmax = new->xmax;
  501.         end->rect.ymax = y;
  502.         end->next = 0;
  503.         new = new->next;
  504.     }
  505.     }
  506.     freeedgelist(opactive);
  507.     opactive = newopactive;
  508.     newopactive = 0;
  509.     return end;
  510. }
  511.  
  512. STATIC operate(op)
  513. int op;
  514. {
  515.     Edge *e, *noa;
  516.     int xpos;
  517.     int in1, in2, res, newres;
  518.  
  519.     if(nop1 == 0) {
  520.     switch(op) {
  521.         case RGN_UNION:
  522.         quickop();
  523.         break;
  524.         case RGN_INTERSECT:
  525.         noa = 0;
  526.         break;
  527.         case RGN_DIFF:
  528.         noa = 0;
  529.         break;
  530.     }
  531.     return;
  532.     } else if(nop2 == 0) {
  533.     switch(op) {
  534.         case RGN_UNION:
  535.         quickop();
  536.         break;
  537.         case RGN_INTERSECT:
  538.         noa = 0;
  539.         break;
  540.         case RGN_DIFF:
  541.         quickop();
  542.         break;
  543.     }
  544.     return;
  545.     }
  546.     newopactive = 0;
  547.     e = active;
  548.     res = 0;
  549.     in1 = in2 = 0;
  550.     noa = 0;
  551.     while(e) {
  552.     xpos = e->xpos; 
  553.     while(e && (e->xpos == xpos)) {
  554.         if(e->op == OP1) 
  555.         in1 = e->side;
  556.         else 
  557.         in2 = e->side;
  558.         e = e->next;
  559.     }
  560.     switch(op) {
  561.         case RGN_UNION:
  562.         newres = in1 | in2;
  563.         break;
  564.         case RGN_INTERSECT:
  565.         newres = in1 & in2;
  566.         break;
  567.         case RGN_DIFF:
  568.         newres = in1 & ~in2;
  569.         break;
  570.     }
  571.     if(newres != res) {
  572.         if(newres) {
  573.         if(!noa) {
  574.             noa = newopactive = newedge();
  575.         } else {
  576.             noa->next = newedge();
  577.             noa = noa->next;
  578.         }
  579.         noa->next = 0;
  580.         noa->xpos = xpos;
  581.         } else { 
  582.         noa->xmax = xpos-1;
  583.         }
  584.         res = newres;
  585.     }
  586.     }
  587. }
  588.  
  589.  
  590. STATIC quickop() 
  591. {
  592.     Edge *e, *noa;
  593.  
  594.     newopactive = 0;
  595.     e = active;
  596.     noa = 0;
  597.     while(e) {
  598.     if(!noa) {
  599.         noa = newopactive = newedge();
  600.     } else {
  601.         noa->next = newedge();
  602.         noa = noa->next;
  603.     }
  604.     noa->next = 0;
  605.     noa->xpos = e->xpos;
  606.     e = e->next;
  607.     noa->xmax = e->xpos-1;
  608.     e = e->next;
  609.     }
  610. }
  611.  
  612. STATIC deleteold(y)
  613. int y;
  614. {
  615.     Edge *e, *temp;
  616.  
  617.     e = active;
  618.     while(e && e->ymax<y) {
  619.     temp = e->next;
  620.     if(e->op == OP1)
  621.         nop1--;
  622.     else
  623.         nop2--;
  624.     freeedge(e);
  625.     e = temp;
  626.     }
  627.     active = e;
  628.     if(!e) {
  629.     endactive = 0;
  630.     return;
  631.     }
  632.     while(e->next) {
  633.     if(e->next->ymax<y) {
  634.         temp = e->next;
  635.         if(temp == endactive)
  636.         endactive = e;
  637.         e->next = temp->next;
  638.         if(temp->op == OP1)
  639.         nop1--;
  640.         else
  641.         nop2--;
  642.         freeedge(temp);
  643.     } else
  644.         e = e->next;
  645.     }
  646. }
  647.  
  648. STATIC rctlist *addtoactive(y,rl,op)
  649. int y;
  650. rctlist *rl;
  651. int op;
  652. {
  653.     Edge *e;
  654.  
  655.     while(rl && rl->rect.ymin <= y) {
  656.     e = newedge();
  657.         e->side = LEFT;
  658.     e->xpos = rl->rect.xmin;
  659.     e->ymax = rl->rect.ymax;
  660.     e->op = op;
  661.     e->rect = rl;
  662.     addedge(e);
  663.     e = newedge();
  664.         e->side = RIGHT;
  665.     e->xpos = rl->rect.xmax+1;
  666.     e->ymax = rl->rect.ymax;
  667.     e->op = op;
  668.     e->rect = rl;
  669.     addedge(e);
  670.     rl = rl->next;
  671.     if(op == OP1)
  672.         nop1 += 2;
  673.     else
  674.         nop2 += 2;
  675.     }
  676.     return rl;
  677. }
  678.  
  679. STATIC addedge(e)
  680. Edge *e;
  681. {
  682.     Edge *l;
  683.     int xpos;
  684.  
  685.     xpos = e->xpos;
  686.     if(!active) {
  687.     e->next = active;
  688.     active = e;
  689.     endactive = e;
  690.     return;
  691.     } else if (active->xpos >= xpos) {
  692.     e->next = active;
  693.     active = e;
  694.     return;
  695.     } else if(xpos >= endactive->xpos) {
  696.     e->next = 0;
  697.     endactive->next = e;
  698.     endactive = e;
  699.     return;
  700.     } else {
  701.     l = active;
  702.     while(l->next) {
  703.         if(l->next->xpos > xpos) {
  704.         e->next = l->next;
  705.         l->next = e;
  706.         return;
  707.         }
  708.         l = l->next;
  709.     }
  710.     e->next = 0;
  711.     l->next = e;
  712.     endactive = e;
  713.     return;
  714.     }
  715. }
  716.  
  717. STATIC nexty(rl1,rl2)
  718. rctlist *rl1, *rl2;
  719. {
  720.     int y;
  721.     Edge *e;
  722.  
  723.     y = BIGY;
  724.     if(rl1 && (rl1->rect.ymin<y))
  725.     y = rl1->rect.ymin;
  726.     if(rl2 && (rl2->rect.ymin<y))
  727.     y = rl2->rect.ymin;
  728.     e = active;
  729.     while(e) {
  730.     if(e->ymax<y)
  731.          y = e->ymax+1;
  732.     e = e->next;
  733.     }
  734.     return y;
  735. }
  736.  
  737. STATIC quickunion(src1,src2,dst)
  738. rgn *src1, *src2, *dst;
  739. {
  740.     rctlist *rl1, *rl2, *drl, *d;
  741.  
  742.     rl1 = src1->rects;
  743.     rl2 = src2->rects;
  744.     drl = 0;
  745.     while(rl1 || rl2) {
  746.     if(!rl1 && rl2) {
  747.         d = rl2;
  748.         rl2 = rl2->next;
  749.     } else if(!rl2 && rl1) {
  750.         d = rl1;
  751.         rl1 = rl1->next;
  752.     } else if(rl1->rect.ymin<rl2->rect.ymin) {
  753.         d = rl1;
  754.         rl1 = rl1->next;
  755.     } else {
  756.         d = rl2;
  757.         rl2 = rl2->next;
  758.     }
  759.     if(!drl) {
  760.         dst->rects = drl = newrl();
  761.         *drl = *d;
  762.         drl->next = 0;
  763.     } else {
  764.         drl->next = newrl();
  765.         drl = drl->next;
  766.         *drl = *d;
  767.         drl->next = 0;
  768.     }
  769.     }
  770.     rgnsetdomain(dst);
  771. }
  772.  
  773. STATIC Edge *newedge()
  774. {
  775.     Edge *e;
  776.  
  777.     if(!fedges) {
  778.     int i;
  779.  
  780.         e = (Edge *)mymalloc(NINCHUNK*sizeof(Edge));
  781.         for(i=0; i<NINCHUNK; i++)
  782.         freeedge(e++);
  783.     }
  784.     e = fedges;
  785.     fedges = fedges->next;
  786.     return e;
  787. }
  788.  
  789. STATIC freeedge( e )
  790. Edge *e;
  791. {
  792.    if( e ) {
  793.        e->next = fedges;
  794.        fedges = e;
  795.    }
  796. }
  797.  
  798. STATIC freeedgelist(edges)
  799. Edge *edges;
  800. {
  801.     Edge *e, *ne;
  802.  
  803.     e = edges;
  804.     while(e) {
  805.     ne = e->next;
  806.     freeedge(e);
  807.     e = ne;
  808.     }
  809. }
  810.  
  811. STATIC rctlist *newrl()
  812. {
  813.     rctlist *rl;
  814.  
  815.     if(!frls) {
  816.     int i;
  817.  
  818.         rl = (rctlist *)mymalloc(NINCHUNK*sizeof(rctlist));
  819.         for(i=0; i<NINCHUNK; i++)
  820.         freerl(rl++);
  821.     }
  822.     rl = frls;
  823.     frls = frls->next;
  824.     return rl;
  825. }
  826.  
  827. STATIC freerl( rl )
  828. rctlist *rl;
  829. {
  830.    if( rl ) {
  831.        rl->next = frls;
  832.        frls = rl;
  833.    }
  834. }
  835.  
  836. STATIC freerectlist(r)
  837. rgn *r;
  838. {
  839.     rctlist *rl, *nrl;
  840.  
  841.     rl = r->rects;
  842.     while(rl) {
  843.     nrl = rl->next;
  844.     freerl(rl);
  845.     rl = nrl;
  846.     }
  847.     r->rects = 0;
  848. }
  849.